﻿using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using SimpleORM.Model.DataBaseModel.SYSModelmain;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace SimpleORM.Infrastructure.Concurrency
{
    /// <summary>
    /// 接口防统一操作并行，造成数据异常
    /// </summary>
    /// <description>防止在顶峰流量下服务器，网络原因造成请求在程序中阻塞后并行执行，
    /// 在需要处理的接口添加《[ServiceFilter(typeof(SemaphoreActionFilter))]》防重复特性，处于初始测试中<description>
    /// <author>yun</author>
    /// <created>2023-07-09</created>
    /// <modified>2023-07-09</modified>
    [MyCustomAttribute]
    [Service(ServiceLifetime.Scoped)]
    public class SemaphoreActionFilter : IAsyncActionFilter
    {
        private static readonly ConcurrentDictionary<string, SemaphoreSlim> Semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();

        private static readonly object LockObject = new object();

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //获取请求头
            //获取请求ID
            string HeaderRequestId = context.HttpContext.Request.Headers["RequestId"].ToString() ?? "NAV";
            if (HeaderRequestId=="")
            {
                HeaderRequestId = "NAV";
            }
            //获取商户或用户ID，ID为自定义
            string HeaderReq_id = context.HttpContext.Request.Headers["Req_id"].ToString() ?? "NAV";
            if (HeaderReq_id == "")
            {
                HeaderReq_id = "NAV";
            }
            // 获取请求体内容
            string requestBody = JsonConvert.SerializeObject(context.ActionArguments).ToString();
            if (requestBody == "")
            {
                requestBody = "NAV";
            }

            // 根据请求Url+请求体生成对应的信号量键值value
            //$"{HeaderReq_id}:{context.HttpContext.Request.Path}:{requestBody}"; 用户DI+请求Url+请求体
            string semaphoreValue = $"{context.HttpContext.Request.Path}:{requestBody}";

            //根据value生成对应的信号量键值
            string semaphoreKey = GetKeyFromRequestBody(semaphoreValue);

            //Guid guid = Guid.NewGuid();
            //semaphoreKey = "123"+ guid;
            // 从字典中获取或添加信号量
            var semaphore = Semaphores.GetOrAdd(semaphoreKey, _ => new SemaphoreSlim(1));//设置最大一个

            // 请求排队逻辑
            await semaphore.WaitAsync();

            try
            {
                //// 输出首次调用或重复调用
                //if (semaphore.CurrentCount == 1) // 当信号量当前计数为1时，表示首次调用
                //{
                //    Console.WriteLine("首次调用");
                //}
                //else // 当信号量当前计数不为1时，表示重复调用
                //{
                //    Console.WriteLine("重复调用");
                //}

                // 执行下一个过滤器或控制器动作
                await next();
            }
            finally
            {
                // 释放信号量
                semaphore.Release();

                // 根据实际情况，可以移除已经执行完的信号量，以减少字典的大小
                lock (LockObject)
                {
                    if (semaphore.CurrentCount == 1)
                    {
                        Semaphores.TryRemove(semaphoreKey, out _);
                    }
                }
            }
        }
        /// <summary>
        /// 根据内容生成key
        /// </summary>
        /// <param name="requestBody"></param>
        /// <returns></returns>
        private string GetKeyFromRequestBody(string requestBody)
        {
            return ComputeHash(requestBody);
        }

        /// <summary>
        /// 生成哈希值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private string ComputeHash(string input)
        {
            using (var sha256 = SHA256.Create())
            {
                var bytes = Encoding.UTF8.GetBytes(input);
                var hashBytes = sha256.ComputeHash(bytes);
                return BitConverter.ToString(hashBytes).Replace("-", "");
            }
        }

    }
}
